package org.example.service;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.example.entity.User;
import org.example.mapper.UserMapper;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.util.concurrent.*;

/**
 * TODO 类功能介绍及重点或容易混淆点的说明。
 *
 * @version 1.0 2023/5/20 10:17 龙小南 新建类[说明]
 * @author: 龙小南
 * @Date: 2023/5/20 10:17
 * @Version 1.0[当前版本号]
 */

@Slf4j
@Service
public class UserService {

    private final ReactiveRedisTemplate<String, String> redisTemplate;

    private final UserMapper userMapper;

    public UserService(ReactiveRedisTemplate<String, String> redisTemplate, UserMapper userMapper) {
        this.redisTemplate = redisTemplate;
        this.userMapper = userMapper;
    }

    public Mono<User> getUserById1(Long id) {
//        return Mono.fromCallable(() -> userMapper.selectById(id)).subscribeOn(Schedulers.boundedElastic());
        return Mono.fromCallable(() -> userMapper.selectById(id));
    }

    public Mono<User> getUserById3(Long id) {
        String key = "user:" + id;
        return redisTemplate.opsForValue().get(key).flatMap(userJson -> {
            // 从redis中获取user，获取到则直接返回
            try {
                return Mono.just(new ObjectMapper().readValue(userJson, User.class));
            } catch (Exception e) {
                return Mono.error(e);
            }
        }).switchIfEmpty(Mono.defer(() -> {
            // 否则从mysql中查询出来再设置到redis
            return this.getUserById1(id).doOnNext(user -> {
                try {
                    String userJson = new ObjectMapper().writeValueAsString(user);
                    redisTemplate.opsForValue().set("user:" + id.toString(), userJson).subscribe();
                } catch (JsonProcessingException e) {
                    throw new RuntimeException();
                }
            });
        }));
    }

    public Flux<User> listUsers() {
        return Flux.defer(() -> Flux.fromIterable(userMapper.selectList(null)));
    }

    public Mono<User> createUser(User user) {
        return Mono.fromCallable(() ->{
            create(user);
            return user;
        });
    }

    public User create(User user) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        userMapper.insert(user);
        return user;
    }

    ThreadFactory build = (new ThreadFactoryBuilder()).setNameFormat("test_service_executor-%d").build();
    private ExecutorService executorService = new ThreadPoolExecutor(4, 50, 0L, TimeUnit.MILLISECONDS
            , new LinkedBlockingQueue(131072), build, new ThreadPoolExecutor.AbortPolicy());
    public CompletableFuture<User> createUser2(User user) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.error("xxxxxx");
            userMapper.insert(user);
            return user;
        });
    }

    public Mono<User> updateUser(User user) {
        return Mono.fromCallable(() -> {
            int affectedRows = userMapper.updateById(user);
            if(affectedRows > 0){
                return user;
            }else{
                throw new RuntimeException("更新失败");
            }
        });
    }

    public Mono<Void> deleteUser(Long userId) {
        return Mono.fromRunnable(() -> userMapper.deleteById(userId));
    }
}
